﻿using System;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
using IServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;

namespace JH.GladeSharpCodeGenerator
{
    [ComVisible(true)]
    public abstract class BaseCodeGeneratorWithSite : BaseCodeGenerator, IObjectWithSite, IDisposable
    {
        private object _site;

        protected static string CreateExceptionMessage(Exception exception)
        {
            var strBuilder = new StringBuilder(exception.Message ?? "");

            for (var innerExcept = exception.InnerException; innerExcept != null; innerExcept = innerExcept.InnerException)
                if (!string.IsNullOrEmpty(innerExcept.Message))
                    strBuilder.AppendLine(" " + innerExcept.Message);

            return strBuilder.ToString();
        }

        protected object GetService(Guid service)
        {
            return SiteServiceProvider.GetService(service);
        }

        protected object GetService(Type service)
        {
            return SiteServiceProvider.GetService(service);
        }

        public virtual void GetSite(ref Guid riid, out IntPtr ppvSite)
        {
            if (_site == null)
            {
                Marshal.ThrowExceptionForHR(-2147467259);
            }
            var sitePtr = Marshal.GetIUnknownForObject(_site);
            IntPtr ppvSiteTmp;
            Marshal.QueryInterface(sitePtr, ref riid, out ppvSiteTmp);
            if (ppvSiteTmp == IntPtr.Zero)
            {
                Marshal.ThrowExceptionForHR(-2147467262);
            }
            ppvSite = ppvSiteTmp;
        }

        public virtual void SetSite(object pUnkSite)
        {
            _site = pUnkSite;
            _serviceProvider = null;
        }

        private ServiceProvider _serviceProvider;
        private ServiceProvider SiteServiceProvider
        {
            get
            {
                if (_serviceProvider == null)
                {
                    var siteServiceProvider = _site as IServiceProvider;
                    _serviceProvider = new ServiceProvider(siteServiceProvider);
                }
                return _serviceProvider;
            }
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing && _serviceProvider != null)
            {
                _serviceProvider.Dispose();
                _serviceProvider = null;
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}
